﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Cassandraemon.Operators;
using Apache.Cassandra;

namespace Cassandraemon
{
    public class CassandraExecuteEventArgs
        : EventArgs
    {
        #region Constructors

        public CassandraExecuteEventArgs(
            object result,
            TimeSpan elapsed)
        {
            this._Result = result;
            this._Elapsed = elapsed;
        }

        public CassandraExecuteEventArgs(
            object result,
            TimeSpan elapsed,
            Cassandra.Client client,
            string method,
            string columnFamilyName)
            : this(result, elapsed)
        {
            this._TraceDataArray = new [] {
                client.HostName(),
                method,
                columnFamilyName,
            };
        }

        public CassandraExecuteEventArgs(
            object result,
            TimeSpan elapsed,
            object[] data)
            : this(result, elapsed)
        {
            this._TraceDataArray = data;
        }

        #endregion

        readonly object _Result;
        readonly TimeSpan _Elapsed;

        public object Result { get { return _Result; } }
        public TimeSpan Elapsed { get { return _Elapsed; } }
        public Exception Exception { get { return _Result as Exception; } }

#if TRACE
        object[] _TraceDataArray;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public object[] TraceDataArray
        {
            get
            {
                var value = this._TraceDataArray;
                if (value != null)
                {
                    return value;
                }

                var list = new List<object>(16);
                this.GetTraceData(list);

                value = list.ToArray();
                this._TraceDataArray = value;
                return value;
            }
        }

        protected virtual void GetTraceData(List<object> data)
        {
            data.Add(this._Elapsed);
            data.Add(this._Result);
        }
#endif

        #region CassandraOperatorBase

        internal static CassandraExecuteEventArgs FromOperation<T>(
            CassandraOperatorBase<T> op,
            object result,
            Stopwatch sw)
        {
            return new CassandraOperatorExecuteEventArgs<T>(op, result, sw);
        }

        class CassandraOperatorExecuteEventArgs<T>
            : CassandraExecuteEventArgs
        {
            public CassandraOperatorExecuteEventArgs(
                CassandraOperatorBase<T> op,
                object result,
                Stopwatch sw)
                : base(result, sw.Elapsed)
            {
                this._Operator = op;
            }

            readonly CassandraOperatorBase<T> _Operator;

#if TRACE
            protected override void GetTraceData(List<object> data)
            {
                base.GetTraceData(data);
                this._Operator.GetTraceData(data);
            }
#endif
        }

        #endregion
    }
}
